#pragma once
// ref: https://github.com/chanfun-ren/ChanfunRpc
// ref: https://my.oschina.net/u/3312209/blog/4313738

#include <vector>
#include <sstream>
#include <algorithm>
#include <cstdint>
#include <utility>
#include <tuple>
#include <type_traits>
namespace
{
// ref:https://stackoverflow.com/questions/25123458/is-trivially-copyable-is-not-a-member-of-std
#if __linux__ && ((__GNUG__ && __GNUC__ < 5) || __cplusplus < 201402L) // for C++11
// ref https://zhuanlan.zhihu.com/p/27186999
namespace std14 {
    template <class T, T...Ints>
    class integer_sequence {
    public:
        using value_type = T;
        static_assert(std::is_integral<value_type>::value,
            "not integral type");
        static constexpr std::size_t size() noexcept {
            return sizeof...(Ints);
        }
    };
    template <std::size_t...Inds>
    using index_sequence = integer_sequence<std::size_t, Inds...>;

    namespace Detail_ {

        template <class T, T Begin, T End, bool>
        struct IntSeqImpl {
            using TValue = T;
            static_assert(std::is_integral<TValue>::value,
                "not integral type");
            static_assert(Begin >= 0 && Begin < End,
                "unexpected argument (Begin<0 || Begin<=End)");

            template <class, class>
            struct IntSeqCombiner;

            template <TValue...Inds0, TValue...Inds1>
            struct IntSeqCombiner<integer_sequence<TValue, Inds0...>,
                integer_sequence<TValue, Inds1...>> {
                using TResult = integer_sequence<TValue, Inds0..., Inds1...>;
            };

            using TResult = typename IntSeqCombiner
                <typename IntSeqImpl<TValue, Begin, Begin + (End - Begin) / 2,
                (End - Begin) / 2 == 1>::TResult,
                typename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End,
                (End - Begin + 1) / 2 == 1>::TResult>
                ::TResult;
        };

        template <class T, T Begin>
        struct IntSeqImpl<T, Begin, Begin, false> {
            using TValue = T;
            static_assert(std::is_integral<TValue>::value,
                "not integral type");
            static_assert(Begin >= 0, "unexpected argument (Begin<0)");
            using TResult = integer_sequence<TValue>;
        };

        template <class T, T Begin, T End>
        struct IntSeqImpl<T, Begin, End, true> {
            using TValue = T;
            static_assert(std::is_integral<TValue>::value,
                "not integral type");
            static_assert(Begin >= 0, "unexpected argument (Begin<0)");
            using TResult = integer_sequence<TValue, Begin>;
        };
    }

    template <class T, T N>
    using make_integer_sequence =
        typename Detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult;

    template <std::size_t N>
    using make_index_sequence = make_integer_sequence<std::size_t, N>;

    template<class... T>
    using index_sequence_for = make_index_sequence<sizeof...(T)>;
}
///////////////////////////
    #define IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T)
    #define MAKE_INDEX_SEQUENCE std14::make_index_sequence
    #define INDEX_SEQUENCE std14::index_sequence
#else
    #define IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
    #define MAKE_INDEX_SEQUENCE std::make_index_sequence
    #define INDEX_SEQUENCE std::index_sequence
#endif

// 可平凡复制 
template <typename T, typename std::enable_if<IS_TRIVIALLY_COPYABLE(T), int>::type N = 0>
void serialize(std::ostream & os, const T & val)  { 
    os.write((const char *)&val,sizeof(T)); 
} 

// pair
template <typename K, typename V>
void serialize(std::ostream & os, const std::pair<K, V> & val) {
    serialize(os, val.first);
    serialize(os, val.second);
}

// std::string
void serialize(std::ostream & os, const std::string &val) {
    size_t size = val.size();
    os.write((const char *)&size, sizeof(size));
    os.write((const char *)val.data(), size * sizeof(typename std::string::value_type));
}

//容器 
template <typename T, typename std::enable_if< std::is_same<typename std::iterator_traits<typename T::iterator>::value_type, typename T::value_type>::value
    , int>::type N = 0> 
void serialize(std::ostream & os, const T & val) {
    size_t size = val.size();
    os.write((const char *)&size, sizeof(size_t));
    for (auto & v : val) {
        serialize(os, v); 
    } 
}


// tuple
template<typename T>
int _Serialize(std::ostream & os, T& val) {
    serialize(os, val);
    return 0;
}

template<typename Tuple, std::size_t... I>
void _Serialize(std::ostream & os, Tuple& tup, INDEX_SEQUENCE<I...>) {
    std::initializer_list<int>{_Serialize(os, std::get<I>(tup))...};
}


template <typename...Args>
void serialize(std::ostream & os, const std::tuple<Args...>& val) {
    _Serialize(os, val, MAKE_INDEX_SEQUENCE<sizeof...(Args)>{});
}


/*************************************** 反序列化 ***************************************/

// 可平凡复制 
template <typename T,typename std::enable_if<IS_TRIVIALLY_COPYABLE(T), int>::type N = 0>
void deserialize(std::istream & is, T & val) { 
     is.read((char *)&val, sizeof(T)); 
}

// std::string
void deserialize(std::istream & is, std::string &val) {
    size_t size = 0; 
    is.read((char*)&size, sizeof(size_t));
    val.resize(size);
    auto count = size * sizeof(typename std::string::value_type);
    is.read((char *)val.data(), count);
}


//pair
template <typename V>
struct ImpDeserialize {
    template<typename T>
    static void get(std::istream & is, T & val) {
        size_t size = 0;
        is.read((char *)&size, sizeof(size_t));
        for (size_t i = 0; i < size; i++)
        {
            V v;
            deserialize(is, v);
            val.insert(val.end(), v);
        }
    }
};

template <typename K, typename V>
struct ImpDeserialize<std::pair<K, V>> {
    template<typename T>
    static void get(std::istream & is, T & val) {
        size_t size = 0;
        is.read((char *)&size, sizeof(size_t));
        for (size_t i = 0; i < size; i++) {
            K k;
            V v;
            deserialize(is, k);
            deserialize(is, v);
            val.emplace(k, v);
        }
        
    }
};

// 容器 
template <typename T, typename std::enable_if< std::is_same<typename std::iterator_traits<typename T::iterator>::value_type, typename T::value_type>::value
    , int>::type N = 0>
void deserialize(std::istream & is, T & val) {
    ImpDeserialize<typename  T::value_type>::get(is, val);
}


//tuple
template<typename T>
int _Deserialize(std::istream & is, T& val) {
    deserialize(is, val);
    return 0;
}

template<typename Tuple, std::size_t... I>
void _Deserialize(std::istream & is, Tuple& tup, INDEX_SEQUENCE<I...>) {
    std::initializer_list<int>{_Deserialize(is, std::get<I>(tup))...};
}


template <typename...Args>
void deserialize(std::istream & is, std::tuple<Args...>& val) {
    _Deserialize(is, val, MAKE_INDEX_SEQUENCE<sizeof...(Args)>{});
}
}